#ifndef SERVER_SOCKET_H_
#define SERVER_SOCKET_H_

#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <mutex>
#include <atomic>
#include <vector>
#include <string>
#include <thread>
#include <netdb.h>  //NI_MAXHOST
#include <string.h> //memset
#include <unistd.h> //read

#include <iostream>
#include <sstream> // For std::ostringstream

#include <condition_variable>
#include "deviceIdManager.h"

#define PORT 8080
#define BUFFER_SIZE 1024

// 消息类型定义ID
#define MSG_HEARTBEAT 0x00 // 心跳消息
#define MSG_SEND_IP 0x01   // 发送IP地址
#define IP_0X_255 0xff     // 255.255.255.255:00.00
#define PORT_0X_00 0x00

#define MSG_SET_DATA_TYPE 0x11 // 设置数据类型
#define MSG_SET_DATA_MS 0x12   // 设置数据请求长度
#define MSG_SET_PIXESL_WH 0x13 // 设置图像请求分辨率
#define MSG_SET_MODEL 0x14     // 设置模型

#define MSG_SET_CLOSE_SOCKET 0x01 0x00 // 请求断开连接
// #define MSG_ACTIVE_SEND 0x11  // 主动请求数据发送
#define MSG_REQUEST 0x21         // pc请求数据
#define MSG_REQUEST_BATTERY 0x23 // pc请求数据电量信息
// #define MSG_PASSIVE_SEBD 0x13 // 被动请求数据发送
#define ERROR_MSG 0xff   // 解析错误
#define CORRECT_MSG 0xfe // 解析正确

struct MessageHeader
{
    uint8_t msgType;   // 消息类型
    uint8_t msgLength; // 消息长度
};

// 枚举类型定义：请求类型
enum class RequestType : uint16_t
{
    // 二进制值的高字节为 0x00，因此直接用低字节定义
    NONE = 0x0000,
    VIDEO = 0x0001,                  // 请求视频数据
    MIC_AIR = 0x0002,                // 仅请求气导mic数据
    VIDEO_AND_MIC_AIR = 0x0003,      // 请求视频数据和气导mic数据
    MIC_BONE = 0x0004,               // 仅请求骨导mic数据
    VIDEO_AND_MIC_BONE = 0x0005,     // 请求视频数据和骨导mic数据
    MIC_AIR_AND_BONE = 0x0006,       // 请求气导mic数据和骨导mic数据
    VIDEO_MIC_AIR_AND_BONE = 0x0007, // 请求视频数据、气导mic数据和骨导mic数据
    /*
    TAG = 0x0008,                    // 请求视识别标签结果
    VIDEO_AND_TAG = 0x0009,          // 请求视频数据和识别标签结果
    MIC_AIR_AND_TAG = 0x000a,        // 请求气导mic数据和识别标签结果
    VIDEO_MIC_AIR_AND_TAG = 0x000b,  // 请求视频数据、气导mic数据和识别标签结果
    MIC_BONE_AND_TAG = 0x000c,       // 请求骨导mic数据和识别标签结果
    VIDEO_MIC_BONE_AND_TAG = 0x000d, // 请求视频数据、骨导mic数据和识别标签结果
    MIC_AIR_BONE_AND_TAG = 0x000e,   // 请求气导mic数据、骨导mic数据和识别标签结果
    ALL_DATA = 0x000f                // 请求视频数据、气导mic数据、骨导mic数据和识别标签结果
*/
};
enum class RequestTag : uint16_t
{
    NONE = 0x0000,
    TAG = 0x0008, // 请求视识别标签结果
};

// 定义一个结构体包含请求类型、标签、时间长度、版本号 像素宽 像素高
struct Request
{
    RequestType type;    // 请求类型
    RequestTag tag;      // 请求标签
    uint32_t timeLength; // 时间长度 (单位：毫秒)
    int version;         // 版本号
    int pixelsWidth;     // 像素宽
    int pixelsHeigth;    // 像素高

    // 构造函数
    Request(RequestType t = RequestType::NONE, RequestTag tg = RequestTag::NONE,
            int len = 0, int ver = 0, int width = 0, int height = 0)
        : type(t), tag(tg), timeLength(len), version(ver), pixelsWidth(width), pixelsHeigth(height) {}

    // 打印结构体信息的函数
    void printInfo() const
    {
        std::cout << "Request Info:" << std::endl;
        std::cout << "  RequestType: " << static_cast<uint16_t>(type) << std::endl;
        std::cout << "  RequestTag: " << static_cast<uint16_t>(tag) << std::endl;
        std::cout << "  TimeLength: " << timeLength << std::endl;
        std::cout << "  Version: " << version << std::endl;
        std::cout << "  pixelsWidth: " << pixelsWidth << std::endl;
        std::cout << "  pixelsHeigth: " << pixelsHeigth << std::endl;
    }
};

// 连接状态的回调
typedef void(tConnectStateCallback)(bool isConnect);
// 数据请求的回调
typedef void(tMsgCallback)(unsigned char msgType, Request request);

class ServerSocket
{
public:
    ServerSocket();
    ~ServerSocket();

    bool init(tConnectStateCallback connect_state, tMsgCallback msg, int ipSet);
    void run();
    void stop();
    bool sendData(const void *__buf, size_t __n);
    static void log(const std::string &message)
    {
        std::lock_guard<std::mutex> guard(log_mutex);
        printf("%s", message);
    }

private:
    int server_fd;
    static int current_client_socket; // 当前连接的客户端socket
    struct sockaddr_in address;
    int addrlen;
    int subnet;

    pthread_t client_thread;    // 客户端处理线程
    pthread_t heartbert_thread; // 心跳发送线程
    std::vector<pthread_t> threads;

    // 心跳相关变量
    static std::atomic<time_t> last_data_time; // 最后一次数据交互的时间戳
    static std::mutex log_mutex;               // 静态互斥锁用于日志同步

    // 心跳相关成员
    static std::atomic<int> missed_heartbeats;  // 丢失的心跳计数
    static const int MAX_MISSED_HEARTBEATS = 4; // 最大允许丢失的心跳次数

    // 心跳消息标识
    static const std::array<unsigned char, 2> HEARTBEAT_MSG; // 0x00 0x00
    // 检查是否为心跳指令
    static bool isHeartbeat(const unsigned char *data, size_t len);

    // 断开连接消息标识
    static const std::array<unsigned char, 8> CLOSE_SOCKET_MSG; // 0x01 0x06 0xff 0xff 0xff 0xff 0x00 0x00
    // 解析错误指令
    static const std::array<unsigned char, 2> ERROR_SOCKET_MSG; // 0xff 0x00
    // 解析正确指令
    static const std::array<unsigned char, 2> CORRECT_SOCKET_MSG; // 0xfe 0x00
    // 存储剩余未解析的数据
    static std::vector<unsigned char> remainingData;

    static void processReceivedData(const unsigned char *buffer, size_t received_len, int client_socket);

    // 检查是否为断开连接指令
    static bool isCloseCommand(const unsigned char *data, size_t len);
    // 检查是否为设置类：数据类型指令
    static bool isSetDataTypeCommand(const unsigned char *data, size_t len);
    // 检查是否为设置类：模型参数指令
    static bool isSetModelCommand(const unsigned char *data, size_t len);
    // 检查是否为设置类：更改数据请求长度指令
    static bool isSetDataLenCommand(const unsigned char *data, size_t len);
    // 检查是否为设置类：更改图像请求分辨率指令 W H
    static bool isSetPixelsCommand(const unsigned char *data, size_t len);
    // 检查是否为pc端请求主动请求数据发送指令
    static bool isPcRequestCommand(const unsigned char *data, size_t len);
    // 检查是否为pc端请求耳机电量信息指令
    static bool isPcRequestBatteryCommand(const unsigned char *data, size_t len);

    static void *handleClient(void *arg);
    static void *sendHeartbeat(void *arg);

    static std::atomic<bool> broadcasting;       // 是否正在广播
    std::atomic<bool> is_running;                // 服务端是否运行
    std::thread server_thread;                   // 服务器线程
    std::thread broadcast_thread;                // 广播线程
    static std::mutex broadcast_mutex;           // 用于广播线程的互斥锁
    static std::condition_variable broadcast_cv; // 控制广播暂停/继续的条件变量

    // 获取本机 IP 地址
    std::string getLocalIPAddress();
    // 实现 IP 和端口号轮询广播的函数
    void broadcastLoop();
    // 设备编码id
    std::string devicesId;

    inline static int combineBytes(unsigned char high, unsigned char low)
    {
        return (high << 8) | low;
    }
    // 将四个字节合并为一个数字，高位在前
    inline static uint32_t combineTo32Bit(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
    {
        // 高字节在前，低字节在后
        return (static_cast<uint32_t>(byte1) << 24) | // 将第1个字节左移24位
               (static_cast<uint32_t>(byte2) << 16) | // 将第2个字节左移16位
               (static_cast<uint32_t>(byte3) << 8) |  // 将第3个字节左移8位
               static_cast<uint32_t>(byte4);          // 第4个字节保持不动
    }
    inline static RequestType getRequestType(int res)
    {
        // 遍历所有枚举值，检查是否与 res 匹配
        switch (static_cast<RequestType>(res))
        {
        case RequestType::NONE:
            return RequestType::NONE;
        case RequestType::VIDEO:
            return RequestType::VIDEO;
        case RequestType::MIC_AIR:
            return RequestType::MIC_AIR;
        case RequestType::VIDEO_AND_MIC_AIR:
            return RequestType::VIDEO_AND_MIC_AIR;
        case RequestType::MIC_BONE:
            return RequestType::MIC_BONE;
        case RequestType::VIDEO_AND_MIC_BONE:
            return RequestType::VIDEO_AND_MIC_BONE;
        case RequestType::MIC_AIR_AND_BONE:
            return RequestType::MIC_AIR_AND_BONE;
        case RequestType::VIDEO_MIC_AIR_AND_BONE:
            return RequestType::VIDEO_MIC_AIR_AND_BONE;

        default:
            return RequestType::NONE; // 如果没有匹配，返回 NONE
        }
    }
    inline static RequestTag getRequestTag(int res)
    {
        // 遍历所有枚举值，检查是否与 res 匹配
        switch (static_cast<RequestTag>(res))
        {
        case RequestTag::NONE:
            return RequestTag::NONE;
        case RequestTag::TAG:
            return RequestTag::TAG;

        default:
            return RequestTag::NONE; // 如果没有匹配，返回 NONE
        }
    }
};
static ServerSocket serverSocket;

#endif